/*
 *------------------------------------------------------------------------------
 * @File      :    ei_os.h
 * @Date      :    2021-3-20
 * @Author    :    lomboswer <lomboswer@lombotech.com>
 * @Brief     :    Media Interface for MDP(Media Development Platform).
 *
 * Copyright (C) 2020-2021, LomboTech Co.Ltd. All rights reserved.
 *------------------------------------------------------------------------------
 */
#ifndef __LB_OSAL__
#define __LB_OSAL__

#define LB_OSAL_VERSION    "1.0"

#include "os_list.h"
#include "os_ioctl.h"

#define OS_UINT_MAX			(~0U)
#define OS_ULONG_MAX			(~0UL)
#define OS_UINT64_MAX			((usigned long long)~0ULL)
#define OS_INT_MAX			((int)(~0U >> 1))
#define OS_LONG_MAX			((long)(~0UL >> 1))
#define OS_INT64_MAX			((long long)(OS_UINT64_MAX>>1))
#define OS_FUNC_NAME_SIZE		(32U)
#define OS_FUNC_ITEM_SIZE		(65535U)

extern int os_log_write(char *buf, unsigned int count);

#ifdef __EOS__
#define __printf(a, b)		__attribute__((format(printf, a, b)))
#endif

#define os_gfp_kernel    0
#define os_gfp_atomic    1

typedef struct {
	int busy;
	char func_name[OS_FUNC_NAME_SIZE];
	unsigned int line;
	unsigned int size;
	void *addr;
} os_mem_blk_info_t;

typedef struct {
	unsigned int vmalloc_cnt;
	unsigned int vmalloc_max;
	unsigned int vzalloc_cnt;
	unsigned int vzalloc_max;
	unsigned int vfree_cnt;

	unsigned int kmalloc_cnt;
	unsigned int kmalloc_max;
	unsigned int kzalloc_cnt;
	unsigned int kzalloc_max;
	unsigned int kfree_cnt;
	os_mem_blk_info_t *info;
} os_mem_stats_t;

extern void *os_vmalloc(unsigned long size);
extern void *os_vzalloc(unsigned long size);
extern void os_vfree(const void *addr);

extern void *__os_kmalloc(unsigned long size, unsigned int os_gfp_flag,
    const char *func_name, const int line);
extern void *__os_kzalloc(unsigned long size, unsigned int os_gfp_flag,
    const char *func_name, const int line);
extern void __os_kfree(const void *addr, const char *func_name, const int line);

/* #define OS_MEM_LEAK_DBG */

#ifdef OS_MEM_LEAK_DBG
#define os_kmalloc(size, os_gfp_flag) __os_kmalloc(size, os_gfp_flag, __FUNCTION__, __LINE__)
#define os_kzalloc(size, os_gfp_flag) __os_kzalloc(size, os_gfp_flag, __FUNCTION__, __LINE__)
#define os_kfree(addr) __os_kfree(addr, __FUNCTION__, __LINE__)
#else
#define os_kmalloc(size, os_gfp_flag) __os_kmalloc(size, os_gfp_flag, NULL, 0)
#define os_kzalloc(size, os_gfp_flag) __os_kzalloc(size, os_gfp_flag, NULL, 0)
#define os_kfree(addr) do{ \
	if (addr) { \
		__os_kfree(addr, NULL, 0); \
		addr = NULL; \
	} else { \
		os_printk("warning: %s[%d]os_kfree Null pointer!\n", __FUNCTION__, __LINE__); \
	} \
}while(0)

#endif

extern void os_get_mem_stats(os_mem_stats_t *memstats);

/* atomic api */
typedef struct {
    void *atomic;
} os_atomic_t;

#define OSAL_ATOMIC_INIT(i)  { (i) }

extern int os_atomic_init(os_atomic_t *atomic);
extern void os_atomic_destroy(os_atomic_t *atomic);
extern int os_atomic_read(os_atomic_t *v);
extern void os_atomic_set(os_atomic_t *v, int i);
extern int os_atomic_inc_return(os_atomic_t *v);
extern int os_atomic_dec_return(os_atomic_t *v);
extern int os_atomic_add_return(int i, os_atomic_t *v);
extern int os_atomic_sub_return(int i, os_atomic_t *v);

/* semaphore api */
typedef struct os_semaphore {
    void *sem;
} os_semaphore_t;

extern int os_sema_init(os_semaphore_t *sem, int val);
extern void os_down(os_semaphore_t *sem);
extern int os_down_interruptible(os_semaphore_t *sem);
extern int os_down_trylock(os_semaphore_t *sem);
int os_down_timeout(os_semaphore_t *sem, long timeout);
int os_down_killable(os_semaphore_t *sem);
extern void os_up(os_semaphore_t *sem);
extern void os_sema_destroy(os_semaphore_t *sem);


/* mutex api */
typedef struct os_mutex {
    void *mutex;
} os_mutex_t;
extern int os_mutex_init(os_mutex_t *mutex);
extern int os_mutex_lock(os_mutex_t *mutex);
extern int os_mutex_lock_interruptible(os_mutex_t *mutex);
extern int os_mutex_trylock(os_mutex_t *mutex);
extern void os_mutex_unlock(os_mutex_t *mutex);
extern void os_mutex_destroy(os_mutex_t *mutex);

/* spinlock api */
typedef struct os_spinlock {
    void *lock;
} os_spinlock_t;
extern int os_spin_lock_init(os_spinlock_t *lock);
extern void os_spin_lock(os_spinlock_t *lock);
extern int os_spin_trylock(os_spinlock_t *lock);
extern void os_spin_unlock(os_spinlock_t *lock);
extern void os_spin_lock_irqsave(os_spinlock_t *lock, unsigned long *flags);
extern void os_spin_unlock_irqrestore(os_spinlock_t *lock, unsigned long *flags);
extern void os_spin_lock_destroy(os_spinlock_t *lock);

/* kfifo api */
typedef struct os_kfifo {
    void *kfifo;
} os_kfifo_t;
extern int os_kfifo_alloc(os_kfifo_t *fifo, unsigned int size,
		unsigned int os_gfp_flag);
extern void os_kfifo_free(os_kfifo_t *fifo);
extern unsigned int os_kfifo_in(os_kfifo_t *fifo,
	const void *buf, unsigned int len);
extern unsigned int os_kfifo_in_spinlocked(os_kfifo_t *fifo,
	const void *buf, unsigned int len, os_spinlock_t *lock);
extern unsigned int os_kfifo_out(os_kfifo_t *fifo,
	void *buf, unsigned int len);
extern unsigned int os_kfifo_out_spinlocked(os_kfifo_t *fifo,
	void *buf, unsigned int len, os_spinlock_t *lock);
extern void os_kfifo_reset(os_kfifo_t *fifo);
extern unsigned int os_kfifo_len(os_kfifo_t *fifo);
extern unsigned int os_kfifo_avail(os_kfifo_t *fifo);
extern int os_kfifo_is_full(os_kfifo_t *fifo);
extern int os_kfifo_is_empty(os_kfifo_t *fifo);

/* wait api */
typedef int (*os_wait_cond_func_t)(const void *param);

typedef struct os_wait {
    void *wait;
} os_wait_t;
#define ERESTARTSYS        512

extern int os_wait_init(os_wait_t *wait);
extern int os_wait_interruptible(os_wait_t *wait, os_wait_cond_func_t func, void *param);
extern int os_wait_uninterruptible(os_wait_t *wait, os_wait_cond_func_t func, void *param);
extern int os_wait_timeout_interruptible(os_wait_t *wait, os_wait_cond_func_t func, void *param,
					   unsigned long ms);
extern int os_wait_timeout_uninterruptible(os_wait_t *wait, os_wait_cond_func_t func, void *param,
					     unsigned long ms);

#define os_wait_event_interruptible(wait, func, param)                       \
    ({                                                                         \
	int __ret = 0;                                                         \
									       \
	for (;;) {                                                             \
	    if (func(param)) {                                                 \
		__ret = 0;                                                     \
		break;                                                         \
	    }                                                                  \
	    __ret = os_wait_timeout_interruptible(wait, (func), param, 100); \
	    if (__ret < 0)                                                     \
		break;                                                         \
	}                                                                      \
	__ret;                                                                 \
    })

#define os_wait_event_uninterruptible(wait, func, param)          \
    ({                                                              \
	int __ret = 0;                                              \
								    \
	for (;;) {                                                  \
	    if (func(param)) {                                      \
		__ret = 0;                                          \
		break;                                              \
	    }                                                       \
	    __ret = os_wait_uninterruptible(wait, (func), param); \
	    if (__ret < 0)                                          \
		break;                                              \
	}                                                           \
	__ret;                                                      \
    })

#define os_wait_event_timeout_interruptible(wait, func, param, timeout)        \
    ({                                                                           \
	int __ret = timeout;                                                     \
										 \
	if ((func(param)) && !timeout) {                                         \
	    __ret = 1;                                                           \
	}                                                                        \
										 \
	for (;;) {                                                               \
	    if (func(param)) {                                                   \
		__ret = os_msecs_to_jiffies(__ret);                            \
		break;                                                           \
	    }                                                                    \
	    __ret = os_wait_timeout_interruptible(wait, (func), param, __ret); \
	    if (!__ret || __ret == -ERESTARTSYS)                                 \
		break;                                                           \
	}                                                                        \
	__ret;                                                                   \
    })

#define os_wait_event_timeout_uninterruptible(wait, func, param, timeout)        \
    ({                                                                             \
	int __ret = timeout;                                                       \
										   \
	if ((func(param)) && !timeout) {                                           \
	    __ret = 1;                                                             \
	}                                                                          \
										   \
	for (;;) {                                                                 \
	    if (func(param)) {                                                     \
		__ret = os_msecs_to_jiffies(__ret);                              \
		break;                                                             \
	    }                                                                      \
	    __ret = os_wait_timeout_uninterruptible(wait, (func), param, __ret); \
	    if (!__ret || __ret == -ERESTARTSYS)                                   \
		break;                                                             \
	}                                                                          \
	__ret;                                                                     \
    })

extern void os_wakeup(os_wait_t *wait);
extern void os_wait_destroy(os_wait_t *wait);

/* workqueue api */
typedef struct os_work_struct {
    void *work;
    void (*func)(struct os_work_struct *work);
} os_work_struct_t;
typedef void (*os_work_func_t)(struct os_work_struct *work);

extern int os_init_work(struct os_work_struct *work, os_work_func_t func);

#define OSAL_INIT_WORK(_work, _func) os_init_work((_work), (_func))

extern int os_schedule_work(struct os_work_struct *work);
extern int os_flush_work(struct os_work_struct *work);
extern void os_destroy_work(struct os_work_struct *work);

/* shedule */
extern void os_yield(void);

/* interrupt api */
enum os_irqreturn {
    OSAL_IRQ_NONE = (0 << 0),
    OSAL_IRQ_HANDLED = (1 << 0),
    OSAL_IRQ_WAKE_THREAD = (1 << 1),
};

/* for linux */
typedef int (*os_irq_handler_t)(int, void *);
extern int os_request_irq(unsigned int irq, os_irq_handler_t handler,
		os_irq_handler_t thread_fn, const char *name, void *dev);
extern void os_free_irq(unsigned int irq, void *dev);
extern int os_in_interrupt(void);

/* task api */
typedef struct os_task {
    void *task_struct;
    void *func;
    void *data;
#ifdef __EOS__
    u32 should_stop;
#endif
} os_task_t;

extern os_task_t *os_kthread_create(int (*threadfn)(void *data),
		void *data, const char *name);
extern void os_kthread_destroy(os_task_t *task, unsigned int stop_flag);
extern char os_kthread_should_stop(void);

/* string api */
extern char *os_strcpy(char *s1, const char *s2);
extern char *os_strncpy(char *s1, const char *s2, int size);
extern int os_strlcpy(char *s1, const char *s2, int size);
extern char *os_strcat(char *s1, const char *s2);
extern char *os_strncat(char *s1, const char *s2, int size);
extern int os_strlcat(char *s1, const char *s2, int size);
extern int os_strcmp(const char *s1, const char *s2);
extern int os_strncmp(const char *s1, const char *s2, int size);
extern int os_strcasecmp(const char *s1, const char *s2);
extern int os_strncasecmp(const char *s1, const char *s2, int n);
extern char *os_strchr(const char *s, int n);
extern char *os_strnchr(const char *s, int count, int c);
extern char *os_strrchr(const char *s, int c);
extern char *os_strstr(const char *s1, const char *s2);
extern char *os_strnstr(const char *s1, const char *s2, int n);
extern int os_strlen(const char *s);
extern int os_strnlen(const char *s, int size);
extern char *os_strpbrk(const char *s1, const char *s2);
extern char *os_strsep(char **s, const char *ct);
extern int os_strspn(const char *s, const char *accept);
extern int os_strcspn(const char *s, const char *reject);
extern void *os_memset(void *str, int c, int count);
extern void *os_memcpy(void *s1, const void *s2, int count);
extern void *os_memmove(void *s1, const void *s2, int count);
extern void *os_memscan(void *addr, int c, int size);
extern int os_memcmp(const void *cs, const void *ct, int count);
extern void *os_memchr(const void *s, int c, int n);
extern void *os_memchr_inv(const void *s, int c, int n);

extern unsigned long long os_strtoull(const char *cp, char **endp, unsigned int base);
extern unsigned long os_strtoul(const char *cp, char **endp, unsigned int base);
extern long os_strtol(const char *cp, char **endp, unsigned int base);
extern long long os_strtoll(const char *cp, char **endp, unsigned int base);
extern int os_snprintf(char *buf, int size, const char *fmt, ...) __printf(3, 4);
extern int os_scnprintf(char *buf, int size, const char *fmt, ...) __printf(3, 4);
extern int os_sprintf(char *buf, const char *fmt, ...) __printf(2, 3);
extern int os_sscanf(const char *buf, const char *fmt, ...);

/* addr translate */
extern void *os_ioremap(unsigned long phys_addr, unsigned long size);
extern void *os_ioremap_nocache(unsigned long phys_addr, unsigned long size);
extern void *os_ioremap_cached(unsigned long phys_addr, unsigned long size);
extern void os_iounmap(void *addr);

#define os_readl(x) ({unsigned int __v = *((volatile int *)(x)); os_rmb(); __v;})
#define os_writel(v, x) ({os_wmb(); *((volatile int *)(x)) = (v);})

extern unsigned long os_copy_from_user(void *to, const void *from, unsigned long n);
extern unsigned long os_copy_to_user(void *to, const void *from, unsigned long n);

#define OSAL_VERIFY_READ   0
#define OSAL_VERIFY_WRITE  1
extern int os_access_ok(int type, const void *addr, unsigned long size);

/* cache api */
extern void os_flush_dcache_area(void *kvaddr, unsigned long phys_addr, int size);
extern void os_invalid_dcache_area(void *kvirt, unsigned long phys_addr, int size);

/* math api */
extern unsigned long long os_div_u64(unsigned long long dividend, unsigned int divisor);
extern long long os_div_s64(long long dividend, int divisor);
extern unsigned long long os_div64_u64(unsigned long long dividend, unsigned long long divisor);
extern long long os_div64_s64(long long dividend, long long divisor);
extern unsigned long long os_div_u64_rem(unsigned long long dividend, unsigned int divisor);
extern long long os_div_s64_rem(long long dividend, int divisor);
extern unsigned long long os_div64_u64_rem(unsigned long long dividend, unsigned long long divisor);
extern unsigned int os_random(void);
extern unsigned int os_random_int(void);
extern unsigned long os_random_long(void);

#define os_max(x, y) ({                            \
	__typeof__(x) _max1 = (x);                  \
	__typeof__(y) _max2 = (y);                  \
	(void) (&_max1 == &_max2);              \
	_max1 > _max2 ? _max1 : _max2; })

#define os_min(x, y) ({                \
    __typeof__(x) _min1 = (x);          \
     __typeof__(y) _min2 = (y);          \
     (void) (&_min1 == &_min2);      \
     _min1 < _min2 ? _min1 : _min2; })

#define os_abs(x) ({                \
    long ret;                         \
    if (sizeof(x) == sizeof(long)) {  \
	long __x = (x);               \
	ret = (__x < 0) ? -__x : __x; \
    } else {                          \
	int __x = (x);                \
	ret = (__x < 0) ? -__x : __x; \
    }                                 \
    ret;                              \
})

/* barrier */
extern void os_mb(void);
extern void os_rmb(void);
extern void os_wmb(void);
extern void os_smp_mb(void);
extern void os_smp_rmb(void);
extern void os_smp_wmb(void);
extern void os_isb(void);
extern void os_dsb(void);
extern void os_dmb(void);

/* debug */
extern int os_printk(const char *fmt, ...) __printf(1, 2);
extern void os_panic(const char *fmt, const char *fun, int line, const char *);
#define OSAL_BUG() \
    do {           \
    } while (1)

#define OSAL_ASSERT(expr)                       \
    do {                                        \
	if (!(expr)) {                          \
	    os_printk("\nASSERT failed at:\n" \
			"  >Condition: %s\n",   \
		#expr);                         \
	    OSAL_BUG();                         \
	}                                       \
    } while (0)

#define OSAL_BUG_ON(expr)                                                               \
    do {                                                                                \
	if (expr) {                                                                     \
	    os_printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
	    OSAL_BUG();                                                                 \
	}                                                                               \
    } while (0)

/* proc api */
struct os_proc_dir_entry;

typedef struct os_proc_fops {
    int (*open)(struct os_proc_dir_entry *entry);
    int (*read)(struct os_proc_dir_entry *entry);
    int (*write)(struct os_proc_dir_entry *entry, const char *buf, int count, long long *);
    int (*close)(struct os_proc_dir_entry *entry);
} os_proc_fops_t;

typedef struct os_proc_dir_entry {
    char name[50];
    void *entry;
    os_proc_fops_t *fops;
    void *private_data;
    void *seqfile;
} os_proc_entry_t;
extern os_proc_entry_t *os_proc_create(const char *name,
	os_proc_entry_t *parent, os_proc_fops_t *fops);
extern os_proc_entry_t *os_proc_mkdir(const char *name, os_proc_entry_t *parent);
extern void os_proc_remove(os_proc_entry_t *entry, os_proc_entry_t *parent);
extern int os_seq_printf(os_proc_entry_t *entry, const char *fmt, ...) __printf(2, 3);

/* device api */
typedef struct os_dev {
    char name[48];
    void *dev;
    int minor;
    struct os_file_operations *fops;
    struct os_pm_ops *pmops;
} os_dev_t;

typedef struct os_vm {
    void *vm;
} os_vm_area_t;

#define OSAL_POLLIN        0x0001
#define OSAL_POLLPRI       0x0002
#define OSAL_POLLOUT       0x0004
#define OSAL_POLLERR       0x0008
#define OSAL_POLLHUP       0x0010
#define OSAL_POLLNVAL      0x0020
#define OSAL_POLLRDNORM    0x0040
#define OSAL_POLLRDBAND    0x0080
#define OSAL_POLLWRNORM    0x0100

typedef struct os_poll {
    void *poll_table;
    void *data;
} os_poll_t;

struct os_file {
    void *private_data;
};

typedef struct os_file_operations {
    int (*open)(struct os_file *file);
    int (*read)(struct os_file *file, char *buf, int size, long *off);
    int (*write)(struct os_file *file, const char *buf, int size, long *off);
    long (*llseek)(struct os_file *file, long offset, int whence);
    int (*release)(struct os_file *file);
    long (*unlocked_ioctl)(struct os_file *file, unsigned int cmd, unsigned long arg);
    unsigned int (*poll)(struct os_file *file, os_poll_t *os_poll);
    int (*mmap)(struct os_file *file, os_vm_area_t *vm, unsigned long start, unsigned long end, unsigned long vm_pgoff);
#ifdef CONFIG_COMPAT
    long (*compat_ioctl)(struct os_file *file, unsigned int cmd, unsigned long arg);
#endif
} os_file_operation_t;

typedef struct os_pm_ops {
    int (*pm_prepare)(os_dev_t *dev);
    void (*pm_complete)(os_dev_t *dev);
    int (*pm_suspend)(os_dev_t *dev);
    int (*pm_resume)(os_dev_t *dev);
    int (*pm_freeze)(os_dev_t *dev);
    int (*pm_thaw)(os_dev_t *dev);
    int (*pm_poweroff)(os_dev_t *dev);
    int (*pm_restore)(os_dev_t *dev);
    int (*pm_suspend_late)(os_dev_t *dev);
    int (*pm_resume_early)(os_dev_t *dev);
    int (*pm_freeze_late)(os_dev_t *dev);
    int (*pm_thaw_early)(os_dev_t *dev);
    int (*pm_poweroff_late)(os_dev_t *dev);
    int (*pm_restore_early)(os_dev_t *dev);
    int (*pm_suspend_noirq)(os_dev_t *dev);
    int (*pm_resume_noirq)(os_dev_t *dev);
    int (*pm_freeze_noirq)(os_dev_t *dev);
    int (*pm_thaw_noirq)(os_dev_t *dev);
    int (*pm_poweroff_noirq)(os_dev_t *dev);
    int (*pm_restore_noirq)(os_dev_t *dev);
} os_pm_ops_t;

#define OSAL_SEEK_SET      0
#define OSAL_SEEK_CUR      1
#define OSAL_SEEK_END      2

extern os_dev_t *os_device_create(const char *name);
extern int os_device_destroy(os_dev_t *pdev);
extern int os_device_register(os_dev_t *pdev);
extern void os_device_deregister(os_dev_t *pdev);
extern void os_poll_wait(os_poll_t *table, os_wait_t *wait);

/* timer api */
typedef struct os_timer {
    void *timer;
    void (*function)(unsigned long);
    unsigned long data;
} os_timer_t;

typedef struct os_timeval {
    long tv_sec;
    long tv_usec;
} os_timeval_t;

typedef struct os_rtc_time {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_mday;
    int tm_mon;
    int tm_year;
    int tm_wday;
    int tm_yday;
    int tm_isdst;
} os_rtc_time_t;

extern int os_timer_init(os_timer_t *timer, void (*fun)(unsigned long),
	unsigned long data);
extern int os_set_timer(os_timer_t *timer, unsigned long timeout_ms);
extern int os_del_timer(os_timer_t *timer);
extern int os_timer_destroy(os_timer_t *timer);

extern unsigned long os_msleep(unsigned int msecs);
extern void os_usleep_range(unsigned long min, unsigned long max);
extern void os_udelay(unsigned int usecs);
extern void os_mdelay(unsigned int msecs);

extern unsigned int os_get_tickcount(void);
extern void os_gettimeofday(os_timeval_t *tv);
extern void os_gettimestamp(os_timeval_t *tv);

extern void os_rtc_time_to_tm(unsigned long time, os_rtc_time_t *tm);
extern void os_rtc_tm_to_time(os_rtc_time_t *tm, unsigned long *time);
extern int os_rtc_valid_tm(struct os_rtc_time *tm);
extern void os_getjiffies(unsigned long long *pjiffies);
extern unsigned long os_msecs_to_jiffies(const unsigned int m);
extern unsigned int os_jiffies_to_msecs(const unsigned long long j);

/* for file operation flags */
#define OS_O_ACCMODE     00000003
#define OS_O_RDONLY      00000000
#define OS_O_WRONLY      00000001
#define OS_O_RDWR        00000002
#define OS_O_CREAT       00000100
#define OS_O_EXCL        00000200
#define OS_O_NOCTTY      00000400
#define OS_O_TRUNC       00001000
#define OS_O_APPEND      00002000

extern void *os_klib_fopen(const char *filename, int flags, int mode);
extern void os_klib_fclose(void *filp);
extern int os_klib_fwrite(const char *buf, int len, void *filp);
extern int os_klib_fread(char *buf, unsigned int len, void *filp);

#include <stdarg.h>

#ifndef _OSAL_VA_LIST

#define _OSAL_VA_LIST
#define os_va_list       va_list
#define os_va_arg(ap, T) va_arg(ap, T)
#define os_va_end(ap) va_end(ap)
#define os_va_start(ap, A) va_start(ap, A)

#endif

#define NULL_STRING        "NULL"

extern void os_vprintk(const char *fmt, os_va_list args);
extern int os_vsnprintf(char *str, int size, const char *fmt, os_va_list args);

/* platform api */
int os_platform_driver_register(void *drv);
void os_platform_driver_unregister(void *drv);
void *os_platform_get_resource_byname(void *dev, unsigned int type,
					const char *name);
void *os_platform_get_resource(void *dev, unsigned int type,
				 unsigned int num);
int os_platform_get_irq(void *dev, unsigned int num);
int os_platform_get_irq_byname(void *dev, const char *name);

#define os_module_driver(os_driver, os_register, os_unregister, ...) \
    static int __init os_driver##_init(void)                               \
    {                                                                        \
	return os_register(&(os_driver));                                \
    }                                                                        \
    module_init(os_driver##_init);                                         \
    static void __exit os_driver##_exit(void)                              \
    {                                                                        \
	os_unregister(&(os_driver));                                     \
    }                                                                        \
    module_exit(os_driver##_exit);

#define os_module_platform_driver(platform_driver)                   \
    os_module_driver(platform_driver, os_platform_driver_register, \
	os_platform_driver_unregister)

extern int os_platform_clk_prepare_enable_all(void *dev);
extern int os_platform_clk_disable_unprepare_all(void *dev);
extern int os_platform_clk_prepare_enable(void *dev, int index);
extern int os_platform_clk_disable_unprepare(void *dev, int index);
extern int os_platform_clk_set_rate(void *pdev, int index, unsigned long rate);
extern unsigned long os_platform_clk_get_rate(void *pdev, int index);
extern int os_platform_clk_set_parent_rate(void *pdev, int index, unsigned long rate);
extern unsigned long os_platform_clk_get_parent_rate(void *pdev, int index);

/* dma api */
typedef struct os_dma_chan {
	void *dma_chan;
	void *descriptor;
} os_dma_chan_t;

typedef int os_dma_cookie_t;

enum os_dma_direction {
	OS_DMA_MEM_TO_MEM,
	OS_DMA_MEM_TO_DEV,
	OS_DMA_DEV_TO_MEM,
	OS_DMA_DEV_TO_DEV,
	OS_DMA_TRANS_NONE,
};

enum os_dma_buswidth {
	OS_DMA_SLAVE_BUSWIDTH_UNDEFINED = 0,
	OS_DMA_SLAVE_BUSWIDTH_1_BYTE = 1,
	OS_DMA_SLAVE_BUSWIDTH_2_BYTES = 2,
	OS_DMA_SLAVE_BUSWIDTH_3_BYTES = 3,
	OS_DMA_SLAVE_BUSWIDTH_4_BYTES = 4,
	OS_DMA_SLAVE_BUSWIDTH_8_BYTES = 8,
	OS_DMA_SLAVE_BUSWIDTH_16_BYTES = 16,
	OS_DMA_SLAVE_BUSWIDTH_32_BYTES = 32,
	OS_DMA_SLAVE_BUSWIDTH_64_BYTES = 64,
};

enum os_dma_status {
	OS_DMA_COMPLETE,
	OS_DMA_IN_PROGRESS,
	OS_DMA_PAUSED,
	OS_DMA_ERROR,
};

typedef struct os_dma_config {
	enum os_dma_direction direction;
	unsigned long long src_addr;
	unsigned long long dst_addr;
	enum os_dma_buswidth src_addr_width;
	enum os_dma_buswidth dst_addr_width;
	unsigned int src_maxburst;
	unsigned int dst_maxburst;
	unsigned int src_port_window_size;
	unsigned int dst_port_window_size;
	char device_fc;
	unsigned int slave_id;
#ifdef __EOS__
	unsigned int int_type;
	unsigned int trans_type;
#endif
} os_dma_config_t;

typedef struct os_dma_tx_state {
	os_dma_cookie_t last;
	os_dma_cookie_t used;
	unsigned int residue;
} os_dma_tx_state_t;

typedef void (*os_dma_callback)(void *dma_param);

extern os_dma_chan_t *os_dma_channel_request(const char *name);
extern int os_dma_channel_release(os_dma_chan_t *chan);
extern int os_dma_channel_config(os_dma_chan_t *chan, os_dma_config_t *cfg);
extern int os_dma_prep_cyclic(
		os_dma_chan_t *chan, unsigned long long buf_addr,
		unsigned int buf_len, unsigned int period_len,
		enum os_dma_direction dir, unsigned long flags,
		os_dma_callback callback, void *callback_param);
extern int os_dma_prep_memcpy(
		os_dma_chan_t *chan, unsigned long long dest,
		unsigned long long src, unsigned int len,
		unsigned long flags,
		os_dma_callback callback, void *callback_param);
extern os_dma_cookie_t os_dma_submit(os_dma_chan_t *chan);
extern int os_dma_issue_pending(os_dma_chan_t *chan);
extern int os_dma_terminate_sync(os_dma_chan_t *chan);
extern int os_dma_terminate_async(os_dma_chan_t *chan);
extern int os_dma_synchronize(os_dma_chan_t *chan);
extern int os_dma_cookie_status(os_dma_chan_t *chan, os_dma_cookie_t cookie,
			 os_dma_tx_state_t *state);

#endif

